Here is a little background on myself with version control system. I remember using CVS (Concurrent Versions System) as my first repository back in mid-2000 in university. I literally had a very tiny knowledge of what the repository is and why it is required. When I joined my first software company, I started using the SVN (Apache Subversion) extensively. When I used it, it was very flexible in terms of how SVN generates diffs and handling the merges of my codes. I genuinely had an excellent workflow by enforcing the branching per issues and managing the trunk as the latest code setup. I was quite satisfied with it until I was exposed to GIT.
At first, I wasn’t sure whether I am going to get accustomed to GIT partially because I was already very familiar with SVN and there wasn’t much of a motivation to jump off the SVN ship. I eventually moved onto GIT as it was becoming quite popular. After a few years of using GIT, I love it, #nosarcasm. It is not only faster in general, but its fully distributed meaning there is no centralized server to handle the code handling. So when you are coding, commits are very tangible and malleable to the local machines. This is where the rebase
in Git comes really handy. Rebase basically is recreating your work of one branch onto another (or the same). Rebase is really powerful and there are a couple of really handy tasks you can do with rebase. I would like to share some of the daily rebase
tasks I often do.
NOTE: When I am explaining below, I would assume you are already familiar with the GIT flow. Also please note as it is important. Rebase means “copy commits, then try to forget the originals and use the copies instead”. This means “making a new history entirely”. This is the reason why you most likely need a --force
during your push to the remote server. It could be a little annoying for other people to manage their repository linked to the branch I rebased. Since the new commits (after rebase) will have different hash, checking out the latest code by the traditional git pull
is not going to work well. This is why it is best to stay away from rebasing when you are working with multiple people on the same branch. The issue branch is almost always owned and ran by me. So this problem rarely happens to me at least.
Rebase is very handy when you try to merge stuffs. Here is an example using the feature
branch and the master
branch. Let’s say you have a master
branch with X commit point and created a feature branch called feature
. Here is how master branch looks like currently:
I’ve created a feature
branch from this commit and made a few commits on top of it, like below:
Let’s make some complication by adding a commit in the master
branch after this feature
branch was created:
We now have few commits in feature
branch but that does not have all the changes in latest master
.
To put the changes in one place, we have choices between to merge
or rebase
.
master
branch to feature
branch:
$git checkout master
$git pull // gets the latest change in master branch
$git checkout feature
$git merge master
feature
branch. Now when you are ready to merge feature
branch into the master
branch, we can run this command:
$git checkout master
$git merge feature
feature
branch cleanly just by fast forwarding since feature
branch and master
branch is on the same path of commits. However, the dummy commit still follows:
$git checkout feature
$git rebase master
$git checkout master
$git merge feature
feature
branch has the same commits of master
branch plus the commits with the new feature
branch.
master
branch either because it just fast forwarded whatever we have in feature
to be the new master
.
Regardless of a merge or rebase, you will run into the conflict. Some people think the rebase solves conflicts which are not true. You need to deal with conflicts one way or another. Rebase just makes the commits cleaner in my opinion.
Sometimes when you make a typo in your commit message or wording is just sounding not right that you want to change the wording of the commit message. You can use rebase to reword your messages. Initially, you have a feature branch with these commits:
You can then run,
2 is the number of commits you would like to rewrite using rebase, so in this case, it is 2 commits behind. Then there will a page popping up where you can change the pick to a reword:
After you put reword instead pick then save and quit, you are prompted to change your commit wordings in next screen. After you corrected your wording save and quit on that next page. GIT will do the rewrite your history by rebasing. Check your commit logs updated.
Here I showed just an example of rewording one commit. You can, however, reword as many commit messages as you wish.
Many times commits are better with a single commit because simply those commits are related to each other. It will be much more organized once you have these separated out by their own means rather than having multiple commits all crowded. We can use the “squash” feature from the rebase in GIT for this.
With the same setup above, we are in a feature branch of some # of commits:
Run the rebase command again:
Here you can put ‘squash’ instead of ‘pick’:
When you save and quit, you will be prompted to edit commit message, here you can give your reasons to whats being combined or simply keep the oldest commit message. After editing the message, you can see your git log
is displayed in one commit:
Well, obviously there are times when a commit is no longer necessary. You can delete the entire line of unnecessary commit by deleting the entire line using the rebase in GIT.
You can also pick and choose whatever the commits you need to get rid of, let’s say you have a repo with multiple commits:
Say you want the “Change 2” and “Change 4” deleted from this branch. Run the following to cover everything until “Change 2”
When you have a screen popup, delete those commits, “Change 2” and “Change 4”:
After removing those lines, save and quit. You might run into a couple of conflicts in between, resolve them, hit git rebase --acontinue
to complete those tasks.
Once you have done rebasing, those commits should be gone:
These rebase tasks are some of common ones I do daily to make commits happy. Obviously, you are going to get familiar a lot quicker if you start using GIT itself. In addition, there are a couple more rebase tasks you can do such as re-ordering commits, separate out portion of code into a separate commit, “fixup”, or even exec where you can run command within GIT commit. Also, I’d like to add that git commit --amend
is really just a rebase of the most recent commit. If you know the power of amend, extend the power to all the other commits!